#include "../../pch.h"
#include "../REFXMLName.h"
#include "REFNameTable.h"
#include "REFXMLNameTable.h"

namespace BFX
{

static int GetHashCode(const UniString& strName)
{
	int nHashCode = 0;
	if (!strName.IsEmpty())
	{
		for (int i = strName.GetLength() - 1; i >= 0; i--)
		{
			UCHAR ch = strName[i];
			if (ch == ':') break;
			nHashCode += (nHashCode << 7) ^ ch;
		}
		nHashCode -= nHashCode >> 17;
		nHashCode -= nHashCode >> 11;
		nHashCode -= nHashCode >> 5;
	}
	return nHashCode;
}

REFXMLNameTable::REFXMLNameTable(REFXMLDocument* pDoc)
{
	m_pOwnerDocument = pDoc;
	m_pNameTable = pDoc->GetNameTable();
	m_pBuckets = new REF<Entry>[HASH_MASK + 1];
	m_nSize = 0;
}

REFXMLNameTable::~REFXMLNameTable()
{
	Clear();
	delete[] m_pBuckets;
}

REFXMLName* REFXMLNameTable::AddName(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNs)
{
	int nHashCode = GetHashCode(strLocalName);
	int nHashBucket = nHashCode & HASH_MASK;
	Entry* pEntry;

	// lookup entry to find matches
	for (pEntry = m_pBuckets[nHashBucket]; pEntry != NULL; pEntry = pEntry->m_pNext)
	{
		if (pEntry->m_nHashCode == nHashCode
			&& pEntry->m_pXmlName->GetLocalName() == strLocalName
			&& pEntry->m_pXmlName->GetPrefix() == strPrefix
			&& pEntry->m_pXmlName->GetNamespaceURI() == strNs)
			return pEntry->m_pXmlName;
	}

	REFXMLName* pXmlName = REFXMLName::Create(m_pNameTable->Add(strPrefix),
		m_pNameTable->Add(strLocalName),
		m_pNameTable->Add(strNs),
		m_pOwnerDocument);

	pEntry = new Entry(pXmlName, nHashCode, m_pBuckets[nHashBucket]);
	m_pBuckets[nHashBucket] = pEntry;

	return pXmlName;
}

REFXMLName* REFXMLNameTable::GetName(const UniString& strPrefix, const UniString& strLocalName, const UniString& strNs)
{
	int nHashCode = GetHashCode(strLocalName);
	int nHashBucket = nHashCode & HASH_MASK;
	Entry* pEntry;

	// lookup entry to find matches
	for (pEntry = m_pBuckets[nHashBucket]; pEntry != NULL; pEntry = pEntry->m_pNext)
	{
		if (pEntry->m_nHashCode == nHashCode
			&& pEntry->m_pXmlName->GetLocalName() == strLocalName
			&& pEntry->m_pXmlName->GetPrefix() == strPrefix
			&& pEntry->m_pXmlName->GetNamespaceURI() == strNs)
			return pEntry->m_pXmlName;
	}

	return NULL;
}

void REFXMLNameTable::Clear()
{
	if (m_nSize == 0)
		return;
	for (int nHashBucket = 0; nHashBucket < (HASH_MASK + 1); nHashBucket++)
	{
		m_pBuckets[nHashBucket] = NULL;	// don't worry, that's fine.
	}
	m_nSize = 0;
}

}	//	namespace BFX
